package com.eternal.control;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;

import androidx.lifecycle.Observer;

import android.content.Intent;
import android.os.Bundle;

import androidx.annotation.Nullable;

import android.text.Spannable;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.alibaba.android.arouter.facade.annotation.Route;
import com.eternal.base.IConnectAction;
import com.eternal.base.concat.LogExtra;
import com.eternal.base.data.RepositoryInjection;
import com.eternal.base.global.ActivityEvent;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.global.ProgressEvent;
import com.eternal.base.protocol.ProtocolTransformer;
import com.eternal.base.router.RouterFragmentPath;
import com.eternal.base.utils.GuQiangUtil;
import com.eternal.control.databinding.FragmentControlCBindingImpl;
import com.eternal.control.view.GuQiangCycleDialView;
import com.eternal.control.view.UpSpan;
import com.eternal.framework.binding.command.BindingAction;
import com.eternal.framework.bus.Messenger;
import com.eternal.framework.bus.RxBus;
import com.eternal.framework.component.BaseFragment;
import com.eternal.framework.utils.Utils;
import com.eternal.widget.guqiang.DoubleCloseAddLayout;
import com.eternal.widget.guqiang.SingleCloseAddProgressBar;
import com.google.common.primitives.UnsignedBytes;
import com.jakewharton.rxbinding2.view.RxView;

import java.util.concurrent.TimeUnit;

import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import retrofit2.http.HEAD;

@Route(path = RouterFragmentPath.Control.PAGE_CONTROL_C)
public class ControlCFragment extends BaseFragment<FragmentControlCBindingImpl, ControlCModel> implements IConnectAction {
    public static final String REFRESH = "refresh";

    private UpSpan span = new UpSpan(8.5f);
    private boolean isFirstControl = false;

    @Override
    public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return R.layout.fragment_control_c;
    }

    @Override
    public int initVariableId() {
        return BR.CModel;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initListener();
        registerMessage();
        bindingEvent();
        Intent intent = getActivity().getIntent();
        String mac = intent.getStringExtra(ActivityEvent.DEVICE_MAC);
        byte port = intent.getByteExtra(ActivityEvent.DEVICE_PORT, (byte) 0x0);
        viewModel.init(RepositoryInjection.providerDeviceRepository(), mac, port);
        initView();
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        if (hidden) {
            viewModel.stop();
        } else {
            viewModel.start();
        }
    }

    @Override
    public void connected() {
        viewModel.start();
    }

    @Override
    public void disconnected() {
        viewModel.stop();
    }

    @Override
    public void onDestroyView() {
        unregisterMessage();
        viewModel.save();
        super.onDestroyView();
    }

    private void initListener() {
        initTmpListener();
        initHumListener();
        initDialListener();
        initShowListener();
    }

    private void initView() {
        SingleCloseAddProgressBar.Factory factory = new SingleCloseAddProgressBar.Factory() {
            @Override
            public String getText(int value) {
                if (viewModel.info != null && viewModel.info.isDegree) {
                    return Utils.getString(R.string.tip_degree_num, value);
                } else {
                    return Utils.getString(R.string.tip_fah_num, value);
                }
            }
        };
        binding.sbHighTmp.setFactory(factory);
        binding.sbLowTmp.setFactory(factory);
        factory = new SingleCloseAddProgressBar.Factory() {
            @Override
            public String getText(int value) {
                return Utils.getString(R.string.tip_percent_num, value);
            }
        };
        binding.sbHighHum.setFactory(factory);
        binding.sbLowHum.setFactory(factory);
        binding.gqDial.setDeviceC(true);
    }

    private void initDialListener() {
        binding.gqDial.setOnChangeListeners(new GuQiangCycleDialView.OnChangeListeners() {
            @Override
            public void onChangeTouchStart(boolean isStart) {
                viewModel.cancelUpdate();
                if (viewModel.info.isControlTypeByHum) {
                    if (isStart) {
                        if (!binding.sbLowHum.isChecked()) {
                            binding.gqDial.setStart(true);
                            binding.sbLowHum.setChecked(true);
                        }
                    } else {
                        if (!binding.sbHighHum.isChecked()) {
                            binding.gqDial.setEnd(true);
                            binding.sbHighHum.setChecked(true);
                        }
                    }
                } else {
                    if (isStart) {
                        if (!binding.sbLowTmp.isChecked()) {
                            binding.gqDial.setStart(true);
                            binding.sbLowTmp.setChecked(true);
                        }
                    } else {
                        if (!binding.sbHighTmp.isChecked()) {
                            binding.gqDial.setEnd(true);
                            binding.sbHighTmp.setChecked(true);
                        }
                    }
                }
            }

            @Override
            public void onChangeStartAndEnd(int start, int end) {
                if (viewModel.info.isControlTypeByHum) {
                    binding.sbLowHum.setProgress(start);
                    binding.sbHighHum.setProgress(end);
                } else {
                    if (viewModel.info.isDegree) {
                        binding.sbLowTmp.setProgress(start);
                        binding.sbHighTmp.setProgress(end);
                    } else {
                        binding.sbLowTmp.setProgress(start + 32);
                        binding.sbHighTmp.setProgress(end + 32);
                    }
                }
            }

            @Override
            public void onChangeAndEndByTouchEnd(int start, int end) {
                viewModel.sendData();
            }
        });
    }

    private void initTmpListener() {
        binding.layoutTmp.setListener(new DoubleListenerAdapter() {
            @Override
            public void onFirst(int value) {
                viewModel.info.autoHighTmp = UnsignedBytes.checkedCast(value);
                if (!viewModel.info.isControlTypeByHum) {
                    int l = UnsignedBytes.toInt(viewModel.info.autoLowTmp);
                    if (!viewModel.info.isDegree) {
                        value -= 32;
                        l -= 32;
                    }
                    binding.gqDial.initStartOrEndAngle(l, l, value, value);
                }
            }

            @Override
            public void onLast(int value) {
                viewModel.info.autoLowTmp = UnsignedBytes.checkedCast(value);
                if (!viewModel.info.isControlTypeByHum) {
                    int h = UnsignedBytes.toInt(viewModel.info.autoHighTmp);
                    if (!viewModel.info.isDegree) {
                        value -= 32;
                        h -= 32;
                    }
                    binding.gqDial.initStartOrEndAngle(value, value, h, h);
                }
            }

            @Override
            public void onEndFirst(boolean isProgress, int value) {
                viewModel.info.autoHighTmp = UnsignedBytes.checkedCast(value);
                super.onEndFirst(isProgress, value);
                if (viewModel.isRefreshComplete && viewModel.info.isControlTypeByHum) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
            }

            @Override
            public void onEndLast(boolean isProgress, int value) {
                viewModel.info.autoLowTmp = UnsignedBytes.checkedCast(value);
                super.onEndLast(isProgress, value);
                if (viewModel.isRefreshComplete && viewModel.info.isControlTypeByHum) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
            }

            @Override
            public void onFirstChecked(boolean b) {
                viewModel.info.autoHighTmpSwitch = b;
                if (!viewModel.info.isControlTypeByHum) {
                    if (binding.gqDial.getEnd() != b) {
                        binding.gqDial.setEnd(b);
                    }
                } else if (viewModel.isRefreshComplete) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
                super.onFirstChecked(b);
            }

            @Override
            public void onLastChecked(boolean b) {
                viewModel.info.autoLowTmpSwitch = b;
                if (!viewModel.info.isControlTypeByHum) {
                    if (binding.gqDial.getStart() != b) {
                        binding.gqDial.setStart(b);
                    }
                } else if (viewModel.isRefreshComplete) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
                super.onLastChecked(b);
            }
        });
    }

    private void initHumListener() {
        binding.layoutHum.setListener(new DoubleListenerAdapter() {
            @Override
            public void onFirst(int value) {
                viewModel.info.autoHighHum = UnsignedBytes.checkedCast(value);
                if (viewModel.info.isControlTypeByHum) {
                    int h = viewModel.info.autoHighHum;
                    int l = viewModel.info.autoLowHum;
                    binding.gqDial.initStartOrEndAngle(l, l, h, h);
                }
            }

            @Override
            public void onLast(int value) {
                viewModel.info.autoLowHum = UnsignedBytes.checkedCast(value);
                if (viewModel.info.isControlTypeByHum) {
                    int h = viewModel.info.autoHighHum;
                    int l = viewModel.info.autoLowHum;
                    binding.gqDial.initStartOrEndAngle(l, l, h, h);
                }
            }

            @Override
            public void onEndFirst(boolean isProgress, int value) {
                viewModel.info.autoHighHum = UnsignedBytes.checkedCast(value);
                super.onEndFirst(isProgress, value);
                if (viewModel.isRefreshComplete && !viewModel.info.isControlTypeByHum) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
            }

            @Override
            public void onEndLast(boolean isProgress, int value) {
                viewModel.info.autoLowHum = UnsignedBytes.checkedCast(value);
                super.onEndLast(isProgress, value);
                if (viewModel.isRefreshComplete && !viewModel.info.isControlTypeByHum) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
            }

            @Override
            public void onFirstChecked(boolean b) {
                viewModel.info.autoHighHumSwitch = b;
                if (viewModel.info.isControlTypeByHum) {
                    if (binding.gqDial.getEnd() != b) {
                        binding.gqDial.setEnd(b);
                    }
                } else if (viewModel.isRefreshComplete) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
                super.onFirstChecked(b);
            }

            @Override
            public void onLastChecked(boolean b) {
                viewModel.info.autoLowHumSwitch = b;
                if (viewModel.info.isControlTypeByHum) {
                    if (binding.gqDial.getStart() != b) {
                        binding.gqDial.setStart(b);
                    }
                } else if (viewModel.isRefreshComplete) {
                    viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
                }
                super.onLastChecked(b);
            }
        });
    }

    private void bindingEvent() {
        viewModel.show.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                SpannableString spannable = new SpannableString(s);
                spannable.setSpan(span, spannable.length() - 1, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                binding.txtShow.setText(spannable);
            }
        });
        viewModel.controlTypeByHumModel.observe(this, new Observer<Boolean>() {
            @Override
            public void onChanged(@Nullable Boolean result) {
                switchControlType(result, viewModel.isRefreshComplete && isFirstControl);
                if (!isFirstControl) {
                    isFirstControl = true;
                }
            }
        });
    }

    @SuppressLint("CheckResult")
    private void initShowListener() {
        RxView.clicks(binding.txtShow)
                .throttleFirst(1, TimeUnit.SECONDS).subscribe(new Consumer<Object>() {
            @Override
            public void accept(Object o) {
                viewModel.controlTypeByHumModel.setValue(!viewModel.controlTypeByHumModel.getValue());
            }
        });
    }

    private void switchControlType(boolean isControlTypeByHum, final boolean isAnimate) {
        viewModel.info.isControlTypeByHum = isControlTypeByHum;
        viewModel.setControlTypeByHum(isControlTypeByHum);
        //湿度圆环上移到温度圆环360
        binding.txtShow.animate().setDuration(isAnimate ? 1000 : 1).rotationBy(360).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                binding.txtShow.setRotation(0);
                if (viewModel.info.isControlTypeByHum) {
                    if (viewModel.info.isDegree) {
                        viewModel.show.setValue(Utils.getString(R.string.tip_degree_num,
                                ProtocolTransformer.getTmpString(viewModel.info.tmp, true)));
                    } else {
                        viewModel.show.setValue(Utils.getString(R.string.tip_fah_num,
                                ProtocolTransformer.getTmpString(viewModel.info.tmp, false)));
                    }
                } else {
                    viewModel.show.setValue(Utils.getString(R.string.tip_percent_num,
                            ProtocolTransformer.getPer(viewModel.info.hum)));
                }

            }
        }).start();
        binding.gqDial.animate().setDuration(isAnimate ? 1000 : 1).rotationBy(360).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                binding.gqDial.setRotation(0);
                String unit, value;
                if (viewModel.info.isControlTypeByHum) {
                    value = ProtocolTransformer.getPer(viewModel.info.hum);
                    unit = "%";
                } else {
                    if (viewModel.info.isDegree) {
                        unit = "℃";
                        value = ProtocolTransformer.getTmpString(viewModel.info.tmp, viewModel.info.isDegree);
                    } else {
                        unit = "℉";
                        value = ProtocolTransformer.getTmpString(viewModel.info.tmp, viewModel.info.isDegree);
                    }
                }
                binding.gqDial.setTmp(value, unit);
                int h, l;
                if (viewModel.info.isControlTypeByHum) {
                    binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_HUM);
                    h = viewModel.info.autoLowHum;
                    l = viewModel.info.autoHighHum;
                    binding.gqDial.initStartOrEndAngle(h, h, l, l);
                    l = 0;
                    if (viewModel.info.hum != BluetoothKey.EMPTY) {
                        l = Math.round(viewModel.info.hum / 100f);
                    }
                    binding.gqDial.setStatusLineAndCenterText(String.valueOf(l), "");
                } else {
                    if (viewModel.info.isDegree) {
                        binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_TMP_C);
                        h = viewModel.info.autoHighTmp;
                        l = viewModel.info.autoLowTmp;
                    } else {
                        binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_TMP_F);
                        h = UnsignedBytes.toInt(viewModel.info.autoHighTmp) - 32;
                        l = UnsignedBytes.toInt(viewModel.info.autoLowTmp) - 32;
                    }
                    binding.gqDial.initStartOrEndAngle(l, l, h, h);
                    l = ProtocolTransformer.getTmp(viewModel.info.tmp, viewModel.info.isDegree);
                    binding.gqDial.setStatusLineAndCenterText(String.valueOf(l), "");
                }
                if (isAnimate) {//从设备列表进入控制页时，圆盘内温湿度不闪
                    binding.gqDial.startAnimation();
                }
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
            }
        }).start();

        if (isAnimate) {//从设备列表进入控制页时，圆盘内温湿度不闪
            binding.gqDial.startAnimation();
        }

        // 滚动到指定位置
        binding.scContent.post(new Runnable() {
            @Override
            public void run() {
                if (viewModel.info.isControlTypeByHum) {
                    if (isAnimate) {
                        binding.scContent.smoothScrollTo(0, binding.layoutHum.getTop());
                    } else {
                        binding.scContent.scrollTo(0, binding.layoutHum.getTop());
                    }
                } else {
                    if (isAnimate) {
                        binding.scContent.smoothScrollTo(0, binding.layoutTmp.getTop());
                    } else {
                        binding.scContent.scrollTo(0, binding.layoutTmp.getTop());
                    }
                }
            }
        });
    }

    private void registerMessage() {
        Messenger.getDefault().register(this, REFRESH, new BindingAction() {
            @Override
            public void call() {
                if (viewModel.info.isControlTypeByHum) {
                    binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_HUM);
                } else if (viewModel.info.isDegree) {
                    binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_TMP_C);
                } else {
                    binding.gqDial.setModeType(GuQiangCycleDialView.MODE_TYPE_AUTO_TMP_F);
                }
                initAuto();
            }
        });
    }

    private void unregisterMessage() {
        Messenger.getDefault().unregister(this);
    }

    private void initAuto() {
        if (viewModel.info.isDegree) {
            String min = Utils.getString(R.string.tip_min_degree_tmp), max = Utils.getString(R.string.tip_max_degree_tmp);
            binding.sbHighTmp.setValue(min, max, 0, 90);
            binding.sbLowTmp.setValue(min, max, 0, 90);
        } else {
            String min = Utils.getString(R.string.tip_min_fah_tmp), max = Utils.getString(R.string.tip_max_fah_tmp);
            binding.sbHighTmp.setValue(min, max, 32, 162);
            binding.sbLowTmp.setValue(min, max, 32, 162);
        }
        if (viewModel.lastInfo != null && viewModel.isRefreshComplete) {
            if (viewModel.lastInfo.autoHighTmp != viewModel.info.autoHighTmp
                    || viewModel.lastInfo.autoLowTmp != viewModel.info.autoLowTmp
                    || viewModel.lastInfo.autoHighTmpSwitch != viewModel.info.autoHighTmpSwitch
                    || viewModel.lastInfo.autoLowTmpSwitch != viewModel.info.autoLowTmpSwitch) {
                if (viewModel.controlTypeByHumModel.getValue() != null
                        && viewModel.controlTypeByHumModel.getValue()
                        && viewModel.lastInfo.isDegree == viewModel.info.isDegree) {
                    viewModel.controlTypeByHumModel.setValue(false);
                }
            } else if (viewModel.lastInfo.autoHighHum != viewModel.info.autoHighHum
                    || viewModel.lastInfo.autoLowHum != viewModel.info.autoLowHum
                    || viewModel.lastInfo.autoHighHumSwitch != viewModel.info.autoHighHumSwitch
                    || viewModel.lastInfo.autoLowHumSwitch != viewModel.info.autoLowHumSwitch) {
                if (viewModel.controlTypeByHumModel.getValue() == null
                        || !viewModel.controlTypeByHumModel.getValue()) {
                    viewModel.controlTypeByHumModel.setValue(true);
                }
            }
        }

        binding.sbHighTmp.setProgress(UnsignedBytes.toInt(viewModel.info.autoHighTmp));
        binding.sbLowTmp.setProgress(UnsignedBytes.toInt(viewModel.info.autoLowTmp));
        binding.sbHighHum.setProgress(viewModel.info.autoHighHum);
        binding.sbLowHum.setProgress(viewModel.info.autoLowHum);
        binding.sbHighTmp.setChecked(viewModel.info.autoHighTmpSwitch);
        binding.sbLowTmp.setChecked(viewModel.info.autoLowTmpSwitch);
        binding.sbHighHum.setChecked(viewModel.info.autoHighHumSwitch);
        binding.sbLowHum.setChecked(viewModel.info.autoLowHumSwitch);
        int h, l;
        if (viewModel.info.isControlTypeByHum) {
            initDial(ProtocolTransformer.getTime(System.currentTimeMillis()),
                    viewModel.info.humState);
            h = viewModel.info.autoHighHum;
            l = viewModel.info.autoLowHum;
            binding.gqDial.initStartOrEndAngle(l, l, h, h);
            l = 0;
            if (viewModel.info.hum != BluetoothKey.EMPTY) {
                l = Math.round(viewModel.info.hum / 100f);
            }
            binding.gqDial.setStatusLineAndCenterText(String.valueOf(l), "");
        } else {
            initDial(ProtocolTransformer.getTime(System.currentTimeMillis()),
                    viewModel.info.tmpState);
            h = UnsignedBytes.toInt(viewModel.info.autoHighTmp);
            l = UnsignedBytes.toInt(viewModel.info.autoLowTmp);

            if (!viewModel.info.isDegree) {
                h -= 32;
                l -= 32;
                if (h < 0) {
                    h = 0;
                }
                if (l < 0) {
                    l = 0;
                }
            }
            binding.gqDial.initStartOrEndAngle(l, l, h, h);
            l = ProtocolTransformer.getTmp(viewModel.info.tmp, viewModel.info.isDegree);
            binding.gqDial.setStatusLineAndCenterText(String.valueOf(l), "");
        }
    }

    private void initDial(String time, byte status) {
        String value, unit;
        if (viewModel.info.isControlTypeByHum) {
            unit = "%";
            value = ProtocolTransformer.getPer(viewModel.info.hum);
            if (viewModel.info.isDegree) {
                viewModel.show.setValue(Utils.getString(R.string.tip_degree_num,
                        ProtocolTransformer.getTmpString(viewModel.info.tmp, true)));
            } else {
                viewModel.show.setValue(Utils.getString(R.string.tip_fah_num,
                        ProtocolTransformer.getTmpString(viewModel.info.tmp, false)));
            }
        } else {
            if (viewModel.info.isDegree) {
                unit = "℃";
            } else {
                unit = "℉";
            }
            value = ProtocolTransformer.getTmpString(viewModel.info.tmp, viewModel.info.isDegree);
            viewModel.show.setValue(Utils.getString(R.string.tip_percent_num,
                    ProtocolTransformer.getPer(viewModel.info.hum)));
        }
        binding.gqDial.setInnerCircleText(value, unit,
                time, String.valueOf(viewModel.info.fan), status);
    }

    abstract class DoubleListenerAdapter implements DoubleCloseAddLayout.Listener {

        @Override
        public void onFirstDown(boolean isProgress) {
            viewModel.cancelUpdate();
            if (isProgress) {
                binding.gqDial.setEndCanDraging(true);
            } else {
                RxBus.getDefault().post(new ProgressEvent(ProgressEvent.INIT, 50));
            }
        }

        @Override
        public void onLastDown(boolean isProgress) {
            viewModel.cancelUpdate();
            if (isProgress) {
                binding.gqDial.setStartCanDraging(true);
            } else {
                RxBus.getDefault().post(new ProgressEvent(ProgressEvent.INIT, 50));
            }
        }

        @Override
        public void onFirstChecked(boolean b) {
            if (!viewModel.refreshStopped) {
                viewModel.cancelUpdate();
                viewModel.sendData();
            }
        }

        @Override
        public void onLastChecked(boolean b) {
            if (!viewModel.refreshStopped) {
                viewModel.cancelUpdate();
                viewModel.sendData();
            }
        }

        @Override
        public void onEndFirst(boolean isProgress, int value) {
            viewModel.sendData();
            if (isProgress) {
                binding.gqDial.setEndCanDraging(false);
                binding.gqDial.invalidate();
            }
        }

        @Override
        public void onEndLast(boolean isProgress, int value) {
            viewModel.sendData();
            if (isProgress) {
                binding.gqDial.setStartCanDraging(false);
                binding.gqDial.invalidate();
            }
        }
    }
}
